package com.fanshilz.flower2025.apps.admin.sysRoute.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import com.fanshilz.flower2025.apps.admin.sysConfig.req.SysConfigTableReq;
import com.fanshilz.flower2025.apps.admin.sysRoute.req.SysRouteSaveOrUpdateReq;
import com.fanshilz.flower2025.apps.admin.sysRoute.resp.SelectTreeResp;
import com.fanshilz.flower2025.apps.admin.sysRoute.resp.SysRouteTableDetailResp;
import com.fanshilz.flower2025.business.sys.sysRoute.entity.SysRoute;
import com.fanshilz.flower2025.business.sys.sysRoute.service.ISysRouteService;
import com.fanshilz.flower2025.business.sys.sysRouteMeta.entity.SysRouteMeta;
import com.fanshilz.flower2025.business.sys.sysRouteMeta.service.ISysRouteMetaService;
import com.fanshilz.flower2025.framework.exception.CodeException;
import com.fanshilz.flower2025.framework.resp.Resp;
import com.fanshilz.flower2025.framework.resp.TableResp;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import io.github.linpeilie.Converter;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.fanshilz.flower2025.business.sys.sysRoute.entity.table.SysRouteTableDef.SYS_ROUTE;

@RequestMapping("/admin/sysRoute")
@RestController
public class SysRouteController {

    @Resource
    private ISysRouteService sysRouteService;
    @Resource
    private ISysRouteMetaService sysRouteMetaService;
    @Resource
    private Converter converter;

    @PostMapping("/selectTree")
    public Resp<List<Tree<Long>>> selectTree() {
        List<SelectTreeResp> selectTreeResps = sysRouteService.getMapper()
                .selectListWithRelationsByQueryAs(QueryWrapper.create()
                        .select(SYS_ROUTE.ROUTE_ID,
                                SYS_ROUTE.ROUTE_ID.as(SelectTreeResp::getValue),
                                SYS_ROUTE.PARENT_ID), SelectTreeResp.class);

        List<TreeNode<Long>> list = selectTreeResps.stream().map(t -> {
            TreeNode<Long> longTreeNode = new TreeNode<>(t.getRouteId(), t.getParentId(), t.getLabel(), null);
            longTreeNode.setExtra(BeanUtil.beanToMap(t));
            return longTreeNode;
        }).toList();

        List<Tree<Long>> build = TreeUtil.build(list, 0L);

        return Resp.success(build);
    }

    @PostMapping("/remove/{routeId}")
    public Resp<Void> remove(@PathVariable Long routeId) {
        boolean b = sysRouteService.updateById(SysRoute.builder()
                .routeId(routeId)
                .delFlag(true)
                .build());
        Assert.isTrue(b, CodeException::new);
        return Resp.success();
    }

    @Transactional
    @PostMapping("/saveOrUpdate")
    public Resp<Void> saveOrUpdate(@RequestBody @Valid SysRouteSaveOrUpdateReq req) {
        SysRoute sr = converter.convert(req, SysRoute.class);
        boolean b = sysRouteService.saveOrUpdate(sr);
        Assert.isTrue(b, CodeException::new);

        SysRouteMeta srm = converter.convert(req.getMeta(), SysRouteMeta.class);
        if (Objects.isNull(srm.getMetaId())) {
            srm.setRouteId(sr.getRouteId());
        }
        boolean b1 = sysRouteMetaService.saveOrUpdate(srm);
        Assert.isTrue(b1, CodeException::new);

        return Resp.success();
    }

    @PostMapping("/table")
    public Resp<TableResp<SysRouteTableDetailResp>> table(@RequestBody @Valid SysConfigTableReq req) {
        Page<SysRouteTableDetailResp> page = sysRouteService.getMapper()
                .paginateWithRelationsAs(Page.of(req.getCurrent(), req.getPageSize(), req.getTotal()),
                        QueryWrapper.create(), SysRouteTableDetailResp.class);

        List<SysRouteTableDetailResp> records = page.getRecords();
        List<SysRouteTableDetailResp> tree = findChildren(records, 0L);

        return Resp.success(new TableResp<>(tree, page.getTotalRow()));
    }

    public List<SysRouteTableDetailResp> findChildren(List<SysRouteTableDetailResp> routes, Long parentId) {
        List<SysRouteTableDetailResp> newRoutes = new ArrayList<>();

        for (SysRouteTableDetailResp route : routes) {
            if (Objects.equals(route.getParentId(), parentId)) {
                newRoutes.add(route);
                route.setChildren(findChildren(routes, route.getRouteId()));
            }
        }

        return newRoutes;
    }

}
